package com.geek.project.geekswaggerstarter.config;

import com.geek.project.geekswaggerstarter.model.MyGroup;
import com.geek.project.geekswaggerstarter.props.SwaggerProperties;
import io.swagger.models.auth.In;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.builders.RequestParameterBuilder;
import springfox.documentation.oas.annotations.EnableOpenApi;
import springfox.documentation.service.*;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.service.contexts.SecurityContext;
import springfox.documentation.spring.web.plugins.Docket;

import javax.annotation.PostConstruct;
import java.util.*;

@EnableOpenApi
@Configuration
@EnableConfigurationProperties(SwaggerProperties.class)
public class SwaggerAutoConfiguration {

    private SwaggerProperties swaggerProperties;
    private ApplicationContext applicationContext;

    public SwaggerAutoConfiguration(SwaggerProperties swaggerProperties, ApplicationContext applicationContext) {
        this.swaggerProperties = swaggerProperties;
        this.applicationContext = applicationContext;
    }

    /**
     * API 页面上半部分展示信息
     */
    private ApiInfo apiInfo(){
        Contact contact = new Contact(
                swaggerProperties.getContact().getName(),
                swaggerProperties.getContact().getUrl(),
                swaggerProperties.getContact().getEmail());
        return new ApiInfoBuilder()
                .title(swaggerProperties.getTitle())
                .description(swaggerProperties.getDescription())
                .version(swaggerProperties.getVersion())
                .termsOfServiceUrl(swaggerProperties.getTermsOfServiceUrl())
                .contact(contact)
                .license(swaggerProperties.getLicense())
                .licenseUrl(swaggerProperties.getLicenseUrl())
                .extensions(swaggerProperties.getVendorExtensions())
                .build();
    }

    @PostConstruct
    public void generateDocket(){
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory)applicationContext.getAutowireCapableBeanFactory();
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(Docket.class);
        beanDefinitionBuilder.addConstructorArgValue(DocumentationType.OAS_30);
        List<MyGroup> groups = swaggerProperties.getGroups();
        for(int index=0; index<groups.size(); index++){
            String beanName = String.format("docket_%s", index);
            defaultListableBeanFactory.registerBeanDefinition(beanName, beanDefinitionBuilder.getBeanDefinition());
            this.initDocket(beanName, groups.get(index));
        }
    }

    private void initDocket(String beanName, MyGroup group) {
        Docket docket = (Docket) applicationContext.getBean(beanName);
        docket.apiInfo(apiInfo())
                .groupName(group.getGroupName())
                // 授权信息设置，必要的header token等认证信息
                .securitySchemes(securitySchemes())
                // 授权信息全局应用
                .securityContexts(securityContexts())
                // 支持的通讯协议集合
                .protocols(newHashSet("https", "http"))
                .enable(swaggerProperties.getEnabled())
                .select()
                // 选择哪些接口作为swagger的doc发布
                .apis(RequestHandlerSelectors.basePackage(group.getBasePackage()))
                .paths(PathSelectors.any())
                .build();
        // 接口调试地址
        if(swaggerProperties.getHost() !=null && swaggerProperties.getHost().length()>0){
            docket.host(swaggerProperties.getHost());
        }
        // 授权信息全局应用
        if(group.isLogin()){
            docket.globalRequestParameters(getParameters());
        }
    }

    /**
     * 设置授权信息
     */
    private List<SecurityScheme> securitySchemes() {
        ApiKey apiKey = new ApiKey("BASE_TOKEN", swaggerProperties.getTokenName(), In.HEADER.toValue());
        return Collections.singletonList(apiKey);
    }

    /**
     * 授权信息全局应用
     */
    private List<SecurityContext> securityContexts() {
        return Collections.singletonList(
                SecurityContext.builder()
                        .securityReferences(Collections.singletonList(new SecurityReference("BASE_TOKEN", new AuthorizationScope[]{new AuthorizationScope("global", "")})))
                        .build()
        );
    }

    @SafeVarargs
    private final <T> Set<T> newHashSet(T... ts) {
        if (ts.length > 0) {
            return new LinkedHashSet<>(Arrays.asList(ts));
        }
        return null;
    }

    private List<RequestParameter> getParameters() {
        List<RequestParameter> requestParameterList = new ArrayList<>();
        RequestParameter requestParameter = new RequestParameterBuilder()
                .name(swaggerProperties.getTokenName())
                .description("令牌")
                .in(ParameterType.HEADER)
                .required(false)
                .build();
        requestParameterList.add(requestParameter);
        return requestParameterList;
    }


}
